/**
 * 
 */
package edu.umd.clip.jobs;

import java.util.concurrent.locks.*;

/**
 * @author Denis Filimonov <den@cs.umd.edu>
 *
 */
public class Worker extends Thread {
	private JobManager manager;
	private boolean busy;
	private Job currentJob;
	private ReentrantLock lock; 
	private Condition newJob;
	/**
	 * @param manager
	 */
	protected Worker(JobManager manager, String name) {
		super(manager.getWorkersThreadGroup(), name);
		this.manager = manager;
		this.busy = false;
		this.lock = new ReentrantLock();
		newJob = lock.newCondition();
	}
	/* (non-Javadoc)
	 * @see java.lang.Thread#run()
	 */
	@Override
	public void run() {
		while(!isInterrupted()) {
			lock.lock();
			try {
				while(!busy) {
					newJob.await();
				}
			} catch(Exception e) {
				e.printStackTrace();
			} finally {
				lock.unlock();
			}
			//System.out.println("Running job "+currentJob.getName());
			try {
				currentJob.run();
			} catch(Throwable e) {
				System.err.printf("[%s] The job '%s' terminated by an uncaught exception: %s\n", 
						getName(), currentJob.getName(), e.getMessage());
				e.printStackTrace();
			}
			//System.out.println("Done job "+currentJob.getName());
			busy = false;
			manager.finished(this);
		}
	}
	
	protected void postJob(Job job) {
		try {
			lock.lock();
			assert(busy == false);
			currentJob = job;
			busy = true;
			newJob.signal();
		} finally {
			lock.unlock();
		}
	}
	/**
	 * @return the busy
	 */
	protected boolean isBusy() {
		return busy;
	}
	/**
	 * @return the currentJob
	 */
	protected Job getCurrentJob() {
		return currentJob;
	}
	
	@Override
	public String toString() {
		Job job;
		boolean b;
		
		lock.lock();
		job = currentJob;
		b = busy;
		lock.unlock();
		
		return String.format("[%s is %s, currentJob:%s]", this.getName(), 
				b ? "busy"  : "slacking", 
				job == null ? "none" : job.toString());
	}
	

}
